
package com.cws.frame.plugin;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Enumeration;
import java.util.Properties;

import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jfinal.kit.PathKit;
import com.jfinal.kit.StringKit;
import com.jfinal.plugin.IPlugin;

/**
 * @title 		[quartz任务调度插件]
 * @description	[一句话描述]
 * @copyright	Copyright 2013 SHIPING INFO Corporation. All rights reserved.
 * @company		SHIPING INFO.
 * @author		Caspar Du
 * @version		v 1.0
 * @create		2014年5月11日 上午12:06:17
 */
public class QuartzPlugin implements IPlugin {

	private static final Logger logger = LoggerFactory.getLogger(QuartzPlugin.class);

	private SchedulerFactory sf = null;

	private Scheduler sched = null;

	private String config = "job.properties";

	private Properties properties;

//	public QuartzPlugin(String config) {
//
//		this.config = config;
//
//	}

	public QuartzPlugin(SchedulerFactory sf,String config) {
		this.sf = sf;
		if(null!=config){
			this.config = config;
		}
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public boolean start() {

		//sf = new StdSchedulerFactory();
		try {
			sched = sf.getScheduler();
		} catch (SchedulerException e) {
			new RuntimeException(e);
		}

		loadProperties();

		Enumeration<?> enums = properties.keys();
		while (enums.hasMoreElements()) {

			String key = enums.nextElement() + "";
			if (!key.endsWith("job")) {
				continue;
			}

			String cronKey = key.substring(0, key.indexOf("job")) + "cron";

			String enable = key.substring(0, key.indexOf("job")) + "enable";

			if (isDisableJob(enable)) {
				continue;
			}

			String jobClassName = properties.get(key) + "";
			String jobCronExp = properties.getProperty(cronKey) + "";
			Class clazz;
			try {
				clazz = Class.forName(jobClassName);
			} catch (ClassNotFoundException e) {
				throw new RuntimeException(e);
			}

			JobDetail job = newJob(clazz).withIdentity(jobClassName,jobClassName).build();

			CronTrigger trigger = newTrigger().withIdentity(jobClassName, jobClassName).withSchedule(cronSchedule(jobCronExp)).build();

			Date ft = null;

			try {
				ft = sched.scheduleJob(job, trigger);

				sched.start();

			} catch (SchedulerException e) {

				new RuntimeException(e);

			}
			
			logger.info(job.getKey() + " has been scheduled to run at: " + ft

			+ " and repeat based on expression: "

			+ trigger.getCronExpression());
		}
		return true;
	}

	private boolean isDisableJob(String enable) {

		return Boolean.valueOf(properties.get(enable) + "") == false;

	}


	public void loadProperties() {

		properties = new Properties();

		if (StringKit.isBlank(config))
			throw new IllegalArgumentException("Parameter of file can not be blank");
		if (config.contains(".."))
			throw new IllegalArgumentException("Parameter of file can not contains \"..\"");

		InputStream inputStream = null;
		String fullFile; // String fullFile = PathUtil.getWebRootPath() + file;
		if (config.startsWith(File.separator))
			fullFile = PathKit.getWebRootPath() + File.separator + "WEB-INF" + config;
		else
			fullFile = PathKit.getWebRootPath() + File.separator + "WEB-INF" + File.separator + config;

		try {
			inputStream = new FileInputStream(new File(fullFile));
			Properties p = new Properties();
			p.load(inputStream);
			properties = p;
		} catch (FileNotFoundException e) {
			throw new IllegalArgumentException("Properties file not found: " + fullFile);
		} catch (IOException e) {
			throw new IllegalArgumentException("Properties file can not be loading: " + fullFile);
		} finally {
			try {
				if (inputStream != null)
					inputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		if (properties == null)
			throw new RuntimeException("Properties file loading failed: " + fullFile);
		// return properties;
	}

	@Override
	public boolean stop() {

		try {
			sched.shutdown();
		} catch (SchedulerException e) {

			logger.error("shutdown error", e);

			return false;
		}
		return true;
	}

}
